[アップデート] CloudWatch エージェントによる CloudWatch Logs へのログ出力でフィルタリングとログ保持期間の設定ができるようになりました
コンバンハ、千葉(幸)です。
CloudWatch エージェントによる CloudWatch Logs へのログ出力において、ふたつの新機能が使えるようになりました。
ログフィルター式と、ログ保持期間の指定です。
- Amazon CloudWatch Agent adds Support for Log Filter Expressions
- Amazon CloudWatch Agent adds support for Configurable Log Group Retention
前者は必要なログのみ CloudWatch Logs に出力することを可能とし、見通しの良さやコスト削減に寄与します。
後者はログ保持期間を指定したい場合の追加設定が不要になり、特に動的にロググループが作成される場合の管理の手間を減らしてくれます。
助かります。
何が変わったのか
CloudWatch エージェント設定ファイルのlogs
セクションに以下フィールドを追加できるようになりました。
filters
retention_in_days
例えば以下のように書けます。
{ "logs": { "logs_collected": { "files": { "collect_list": [ { "file_path": "/var/log/test", "log_group_name": "/var/log/test", "log_stream_name": "{instance_id}", "filters": [ { "type": "exclude", "expression": "Firefox" }, { "type": "include", "expression": "P(UT|OST)" } ], "retention_in_days": 30 } ] } } } }
いずれのフィールドも 2022/2/26 時点で最新の CloudWatch エージェントでのみ使用できます。S3 リンクからダウンロードできるものは最新バージョンになっていますが、yum でインストールできるものは少し古いバージョンになっているようなので注意してください。
各フィールドの詳細は以下ドキュメントから確認できます。
CloudWatch Logs に出力するログのフィルタリング
これまで CloudWatch エージェントは設定ファイルで指定されたパスのログをすべて CloudWatch Logs へ出力していました。特定のキーワードにマッチするもののみ CloudWatch Logs で取り扱いたいという要件が有った場合、全量が送られることはあまり嬉しくありません。
- ノイズが増えてしまう
- CloudWatch Logs への取り込み、ログの保管で不要な料金が発生する
今回のアップデートにより正規表現を用いてinclude
もしくはexclude
のタイプでフィルターを作成できるようになりました。
例えば以下のように指定したとします。これはドキュメントから引用しました。
"filters": [ { "type": "exclude", "expression": "Firefox" }, { "type": "include", "expression": "P(UT|OST)" } ],
上記の指定をした場合、以下のように機能します。
Firefox
の文字列を含むログイベントはすべて破棄するPUT
もしくはPOST
の文字列を含むログイベントを CloudWatch Logs に出力する- 合致しないログイベントはすべて破棄する
ここで言っている「破棄」とは CloudWatch Logs への出力対象から外すことを指しており、ローカルのログファイルに影響はありません。
expression
で指定できる正規表現パターンは以下に準拠しています。
filters によるフィルタリングにおける注意点
- 正規表現の評価に時間がかかる書き方は避けてください
- CloudWatch エージェントが正規表現のパフォーマンスをチェックしたり評価の実行時間を制限することはありません
- (参考)Regular expression Denial of Service - ReDoS Software Attack | OWASP
- フィルターは上から順番に評価されます
- パフォーマンスの向上のために、複数のフィルターで評価されるログエントリを少なくなるよう順序を決定してください
- 広い範囲で
exclude
するフィルターを優先度高くする
- 広い範囲で
- パフォーマンスの向上のために、複数のフィルターで評価されるログエントリを少なくなるよう順序を決定してください
CloudWatch Logs ロググループのログ保持期間の指定
CloudWatch Logs ロググループではログの保持期間という概念があります。指定した保持期間を経過したログイベントは順次削除されていきます。デフォルトでは保持期間が無期限となっており、ログが溜まり続けていきます。
ログの保存容量に応じて料金が発生するため、保持期間を明示的に指定するケースは多いです。
これまで CloudWatch エージェントの設定と CloudWatch Logs のログ保持期間は独立していたので、管理を工夫してあげる必要がありました。
- 事前にロググループの作成/保持期間の設定を済ませた上でエージェント設定ファイルで出力先に指定する
- 一度 CloudWatch エージェントからログ出力を行った上で、作成されたロググループの保持期間を後から変更する など
CloudWatch エージェント設定ファイルでは動的にロググループ名を指定できる(例えばインスタンス名にするなど)ため、新規のロググループがどんどん作成されるような構成の場合、管理は複雑になります。
今回のアップデートにより、CloudWatch エージェント設定ファイルでログ保持期間を定義できるようになり、自動で設定変更できるようになりました。
保持期間として指定できる値は 1、3、5、7、14、30、60、90、120、150、180、365、400、545、731(2年間)、1827(5年間)、3653(10年間)のいずれかです。
指定しない場合、従来と同様「無期限」となります。
retention_in_days によるログ保持期間の指定の注意点
- CloudWatch エージェントが使用する IAM ロールや IAM ユーザーが以下の権限を有している必要があります
logs:PutRetentionPolicy
- 既存のロググループに
retention_in_days
を指定した場合、設定が上書きされます- 例えばここで
3
を指定した場合、既存のログは 3 日分を残して削除されます
- 例えばここで
- エージェント設定ファイルで同一ロググループの複数のログストリームを定義する場合……
- 一箇所で
logs:PutRetentionPolicy
を定義すれば事足ります - ログストリーム間で異なる
logs:PutRetentionPolicy
を定義するとエラーになります
- 一箇所で
最後について補足すると、以下のような書き方をするとエラーになるよ、ということです。
...... "collect_list": [ { "file_path": "/var/log/testA", "log_group_name": "/var/log/test", "log_stream_name": "streamA", "retention_in_days": 30 }, { "file_path": "/var/log/testB", "log_group_name": "/var/log/test", "log_stream_name": "streamB", "retention_in_days": 90 }, ......
上記の例では二つのコレクションで同一のロググループ/var/log/test
を指定しています。両者で異なるretention_in_days
の値を指定しているため、正しい書き方ではありません。以下のいずれかにする必要があります。
- 一方のコレクションでのみ
retention_in_days
を定義する - 両者のコレクションで同一の
retention_in_days
の値を定義する
保持期間を両者で変えたい、という場合はロググループごと分けてあげる必要があります。
やってみた
冒頭で載せたエージェント設定ファイルを適用し、ログ出力の結果を確認してみます。エージェントのインストールから一連の流れで試していきます。
- CloudWatch エージェントのインストール
- CloudWatch エージェント設定ファイルの適用
- CloudWatch エージェントによるログ出力のテスト
CloudWatch エージェントのインストール、設定ファイルの変更は Systems Manager を利用して行います。以下を参考にしています。
0. EC2 インスタンスのセットアップ
Systems Manager が利用可能なことが前提となっています。今回は以下でセットアップしました。
- amzn2-ami-kernel-5.10-hvm-2.0.20220207.1-x86_64-gp2 からローンチ
- SSMエージェントがインストール済み
- パブリックサブネットに配置しパブリック IP を割り当て
- IAM ロールに
AmazonSSMManagedInstanceCore
を割り当て
インスタンスが利用する IAM ロールには以下も追加でアタッチしています。
CloudWatchAgentServerPolicy
- CloudWatch Logs への出力、パラメータストアからの読み取り
- カスタムポリシー
カスタムポリシーの内訳は以下で、先述の通りログ保持期間を変更するために必要となります。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "logs:PutRetentionPolicy", "Resource": "*" } ] }
1. CloudWatch エージェントのインストール
Systems Manager ランコマンドで SSM ドキュメントAWS-ConfigureAWSPackage
を実行します。
指定するパラメータは以下で、Name
とVersion
を明示的に指定しています。
パラメータ | 値 |
---|---|
Action | Install |
Installation Type | Uninstall and reinstall |
Name | AmazonCloudWatchAgent |
Version | latest |
Additional Arguments | {} ※デフォルト |
実行することでインストールが実行されます。出力を確認すると以下のバージョンの CloudWatch エージェントがインストールされていました。
Initiating arn:aws:ssm:::package/AmazonCloudWatchAgent 1.247350.0b251780 install Plugin aws:runShellScript ResultStatus Success install output: Running sh install.sh create group cwagent, result: 0 create user cwagent, result: 0 Successfully installed arn:aws:ssm:::package/AmazonCloudWatchAgent 1.247350.0b251780
2. CloudWatch エージェント設定ファイルの適用
事前準備としてエージェント設定ファイルをパラメータストアに格納しておきます。現状の IAM ポリシーだと接頭辞AmazonCloudWatch-
を持つパラメータのみ読み取りができるため、今回はAmazonCloudWatch-agent-config
という名称で作成します。
格納した値は冒頭で記載した例と同じく以下です。
{ "logs": { "logs_collected": { "files": { "collect_list": [ { "file_path": "/var/log/test", "log_group_name": "/var/log/test", "log_stream_name": "{instance_id}", "filters": [ { "type": "exclude", "expression": "Firefox" }, { "type": "include", "expression": "P(UT|OST)" } ], "retention_in_days": 30 } ] } } } }
この状態で Systems Manager ランコマンドで SSM ドキュメントAmazonCloudWatch-ManageAgent
を実行します。
パラメータ | 値 |
---|---|
Action | configure |
Mode | ec2 |
Optional Configuration Source | ssm |
Optional Configuration Location | AmazonCloudWatch-agent-config |
Optional Open Telemetry Collector Configuration Source | ssm |
Optional Open Telemetry Collector Configuration Location | (ブランク) |
Optional Restart | yes |
Optional Configuration Location
としてパラメータの名称を指定した以外はデフォルトのままです。
実行することで設定ファイルが適用されます。
出力を確認すると以下のようにログが出ていました。
2022/02/26 07:52:38 Reading json config file path: /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d/ssm_AmazonCloudWatch-agent-config.tmp ... Created symlink from /etc/systemd/system/multi-user.target.wants/amazon-cloudwatch-agent.service to /etc/systemd/system/amazon-cloudwatch-agent.service. Redirecting to /bin/systemctl restart amazon-cloudwatch-agent.service
念のため設定確認
設定が終わった状態で Systems Manager セッションマネージャーでインスタンスに接続し、エージェントの設定内容を確認してみます。
/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.toml
を参照します。
sh-4.2$ cat /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.toml [agent] collection_jitter = "0s" debug = false flush_interval = "1s" flush_jitter = "0s" hostname = "" interval = "60s" logfile = "/opt/aws/amazon-cloudwatch-agent/logs/amazon-cloudwatch-agent.log" logtarget = "lumberjack" metric_batch_size = 1000 metric_buffer_limit = 10000 omit_hostname = false precision = "" quiet = false round_interval = false [inputs] [[inputs.logfile]] destination = "cloudwatchlogs" file_state_folder = "/opt/aws/amazon-cloudwatch-agent/logs/state" [[inputs.logfile.file_config]] file_path = "/var/log/test" from_beginning = true log_group_name = "/var/log/test" log_stream_name = "i-04c7d35135e594a07" pipe = false retention_in_days = 30 [[inputs.logfile.file_config.filters]] expression = "Firefox" type = "exclude" [[inputs.logfile.file_config.filters]] expression = "P(UT|OST)" type = "include" [inputs.logfile.tags] metricPath = "logs" [outputs] [[outputs.cloudwatchlogs]] force_flush_interval = "5s" log_stream_name = "i-04c7d35135e594a07" region = "ap-northeast-1" tagexclude = ["metricPath"] [outputs.cloudwatchlogs.tagpass] metricPath = ["logs"]
ログの保持期間、フィルター設定が意図した通りになっています。
3. CloudWatch エージェントによるログ出力のテスト
インスタンスに接続後/var/log/test
にいくつかのログを出力し、挙動を確認します。
出力するログは以下です。
Firefox PUT Firefox POST Firefox GET Chrome PUT Chrome POST Chrome GET PUT POST GET
フィルターの条件をおさらいすると以下です。
Firefox
の文字列を含むログイベントはすべて破棄するPUT
もしくはPOST
の文字列を含むログイベントを CloudWatch Logs に出力する- 合致しないログイベントはすべて破棄する
root にスイッチしてから以下を実行しました。
[root@ip-192-168-0-96 ~]# cat << _EOF_ >> /var/log/test > Firefox PUT > Firefox POST > Firefox GET > Chrome PUT > Chrome POST > Chrome GET > PUT > POST > GET > _EOF_ [root@ip-192-168-0-96 ~]# cat /var/log/test Firefox PUT Firefox POST Firefox GET Chrome PUT Chrome POST Chrome GET PUT POST GET
CloudWatch Logs ロググループを確認すると、指定した通りの保持期間が設定されています。
ログストリームに出力されたログイベントを確認すると、意図した通りの結果のみが出力されています。
ログのフィルタリング、保持期間の設定の挙動が確認できました!
終わりに
CloudWatch エージェント設定ファイルでフィルター式と保持期間の定義ができるようになった、というアップデートでした。
東京リージョンでは CloudWatch Logs のログ取り込み、保存に以下の料金がかかります。
項目 | 料金 |
---|---|
収集 (データの取り込み) | 0.76USD/GB |
保存 (アーカイブ) | 0.033USD/GB |
フィルターによって取り込む量を減らしたり、保持期間を短く(することを漏れにくく)して保存量を減らしたりとコスト面でも嬉しいアップデートかと思います。
現時点の最新バージョンでしか使用できないという制約はありますが、エージェントの最新化も兼ねて機能の活用を検討してみてはいかがでしょうか。
以上、 チバユキ (@batchicchi) がお送りしました。